#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include <iostream>
#include <list>
#include <cmath>
#include <complex>
#include "../luaMPI.h"

namespace sol {
   template <>
   struct is_automagical< mpi::request_list > : std::false_type {};
}

namespace LuaMPI {
	template<class T>
	void abc(T&,int){

	}
	void open_luaMPI(sol::table& module)
	{
		module.set_function("wait_all", &mpi::wait_all );

		module.new_usertype<mpi::request_list>("request_list"
				,"add", ( void (mpi::request_list::*)(const mpi::request&)) & mpi::request_list::push_back
				,"push_back", ( void (mpi::request_list::*)(const mpi::request&)) & mpi::request_list::push_back
				,"clear", ( void (mpi::request_list::*)(void)) & mpi::request_list::clear
				,"size",[](mpi::request_list* v){
						return (int) v->size();
				}
		);

		sol::table world = module.create("world");
		world.set_function("rank", mpi::world::rank );
		world.set_function("size", mpi::world::size );
		world.set_function("barrier", mpi::world::barrier );

		world.set_function("broadcast", sol::overload(
				sol::resolve<void(std::vector<double> &,int)>( &mpi::world::broadcast<std::vector<double>> )
				,sol::resolve<void(std::vector<std::complex<double>> &,int)>( &mpi::world::broadcast<std::vector<std::complex<double>>> )
				//,sol::resolve<void(double &,int)>( &mpi::world::broadcast<double> )
				)
		);

		world.set_function("send", sol::overload(
				sol::resolve<void(int,int,const std::vector<double>&)>
						( &mpi::world::send<std::vector<double>> )
				,sol::resolve<void(int,int,const std::vector<std::complex<double>>&)>
						( &mpi::world::send<std::vector<std::complex<double>>> )
				)
		);

		world.set_function("recv", sol::overload(
				sol::resolve<void(int,int,std::vector<double>&)>
						( &mpi::world::recv<std::vector<double>> )
				,sol::resolve<void(int,int,std::vector<std::complex<double>>&)>
						( &mpi::world::recv<std::vector<std::complex<double>>> )
			)
		);

		world.set_function("isend", sol::overload(
				sol::resolve< mpi::request (int,int,const std::vector<double>&)>
						( &mpi::world::isend<std::vector<double>> )
				,sol::resolve< mpi::request (int,int,const std::vector<std::complex<double>>&)>
						( &mpi::world::isend<std::vector<std::complex<double>>> )
				,sol::resolve< mpi::request (int,int,const std::vector<std::string>&)>
						( &mpi::world::isend<std::vector<std::string>> )
			)
		);


		world.set_function("irecv", sol::overload(
				sol::resolve< mpi::request (int,int,std::vector<double>&)>
						( &mpi::world::irecv<std::vector<double>> )
				,sol::resolve< mpi::request (int,int,std::vector<std::complex<double>>&)>
					( &mpi::world::irecv<std::vector<std::complex<double>>> )
				,sol::resolve< mpi::request (int,int,std::vector<std::string>&)>
					( &mpi::world::irecv<std::vector<std::string>> )
			)
		);

	}
}
